// Algoritmo de Monte Carlo em Paralelo
#include <stdio.h>
#include <stdlib.h>
#include <gmp.h>
#include <time.h>
#include <pthread.h>

	pthread_mutex_t mutex;
	
	//declaração das variaveis da gmp
	mpf_t ptotal;
	mpf_t pin;
	mpf_t valor_pi;

	double quadrado; // x²+y²

// funcao que calcula a soma do quadrado de dois numeros aleatorios
void *calc_quadrado(){
	double x, y;

	x=drand48(); // numero aleatorio entre 0 e 1
	y=drand48();// numero aleatorio entre 0 e 1
	
	quadrado=x*x+y*y;//numero=x²+y²
	
	pthread_mutex_unlock(&mutex);	
	pthread_exit(NULL);

}

//função que calcula o valor de Pi através de valor_pi= 4*(pin/ptotal);
void *calc_pi(){
	
	pthread_mutex_lock(&mutex);	
	mpf_div(valor_pi,pin,ptotal);// valor_pi= pin/ptotal
	mpf_mul_ui(valor_pi,valor_pi,4);// valor_pi=4*valor_pi
	pthread_mutex_unlock(&mutex);		
	pthread_exit(NULL);
}

// funcao que verifica se o ponto(x,y) está dentro do quarto de circulo
void *comparacao(){
    
	pthread_mutex_lock(&mutex);	
	
	if(quadrado<=1){  //x²+y² <=1
            	mpf_add_ui(pin,pin,1); //pin=pin+1;
      		
		}
	pthread_mutex_unlock(&mutex);	
	pthread_exit(NULL);
	
}


main() {
	int i,n = 25000;
	time_t inicio, fim; // variaveis de tempo
	double tempo;
	
	FILE *fp;

	fp= fopen("pi_paralelo.txt","w");

	time(&inicio); // inicio do tempo de execução
	
	mpf_set_default_prec(33219280);// precisão das variaveis gmp

	//inicialização das variaveis gmp
	mpf_init (ptotal);
	mpf_init (pin);
	mpf_init (valor_pi);
	mpf_set_ui(pin,0);

	//semente para função drand48()
	srand48(time(NULL));

	//declaração das threads
	pthread_t numeros_aleatorios;
	pthread_t compara_quadrado;
	pthread_t PI;
	
	for(i=1;i<=n;i++){
		printf("  \n%d...",i);
	
		// criação das threads 
		pthread_create(&numeros_aleatorios,NULL,calc_quadrado,NULL);
		pthread_create(&compara_quadrado,NULL,comparacao,NULL);
		
		// aguardando final das threads		
		pthread_join (numeros_aleatorios, NULL);
		pthread_join (compara_quadrado, NULL);
	}
  printf("Aguarde...\n");
	mpf_set_ui(ptotal,i);//atribuição de ptotal

	// criação da thread para calculo de Pi	
	pthread_create(&PI,NULL,calc_pi,NULL);
	pthread_join (PI, NULL);// aguardando thread

	time(&fim); // fim de execução
	tempo=difftime(fim, inicio);// calculo de tempo

	//salvando em arquivo Pi com 10 milhões de casas.
	gmp_fprintf(fp,"%.10000000Ff",valor_pi);
	fclose(fp);
	
	printf("\nDemonstracao de apenas 100 casas decimais:");
    	gmp_printf("\npi = %.100Ff\n",valor_pi);
	printf("\nAs 10 milhoes de casas foram gerados no arquivo .txt");
	printf("\n\nTempo de execucao %lf segundos\n",tempo);
	
	//libera memoria	
	mpf_clear(pin);
	mpf_clear(ptotal);
	mpf_clear(valor_pi);
	
}
